package com.java.shop.product.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.java.common.constant.ProductConstant;
import com.java.common.to.SkuHasStockTo;
import com.java.common.to.SpuBoundTo;
import com.java.common.to.es.SkuEsModel;
import com.java.common.utils.PageUtils;
import com.java.common.utils.Query;
import com.java.common.utils.R;
import com.java.shop.product.dao.SpuInfoDao;
import com.java.shop.product.entity.*;
import com.java.shop.product.feign.CouponFeignService;
import com.java.shop.product.feign.ThirdPartFeignService;
import com.java.shop.product.feign.WareFeignService;
import com.java.shop.product.service.*;
import com.java.shop.product.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Slf4j
@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Autowired
    SpuInfoDescService spuInfoDescService;

    @Autowired
    SpuImagesService spuImagesService;

    @Autowired
    ProductAttrValueService productAttrValueService;

    @Autowired
    SkuInfoService skuInfoService;

    @Autowired
    CouponFeignService couponFeignService;

    @Autowired
    BrandService brandService;

    @Autowired
    CategoryService categoryService;

    @Autowired
    AttrService attrService;

    @Autowired
    WareFeignService wareFeignService;

    @Autowired
    ThirdPartFeignService thirdFeignService;



    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );

        return new PageUtils(page);
    }

    @Transactional
    @Override
    public void saveSpuInfo(SpuSaveVo vo) {
        //1.保存spu基本信息   pms_spu_info
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        BeanUtils.copyProperties(vo,spuInfoEntity);
        this.save(spuInfoEntity);

        Long spuId = spuInfoEntity.getId();

        //2.保存spu的描述信息（图片）  pms_spu_info_desc
        SpuInfoDescEntity spuInfoDescEntity = new SpuInfoDescEntity();
        spuInfoDescEntity.setSpuId(spuId);
        spuInfoDescEntity.setDecript(String.join(",",vo.getDecript()));
        spuInfoDescService.save(spuInfoDescEntity);

        //3.保存spu的图片集   pms_spu_images
        List<String> spuImg = vo.getImages();
        spuImagesService.saveImages(spuId,spuImg);

        //4.保存spu的规格参数  pms_product_attr_value
        List<Attr> baseAttrs = vo.getBaseAttrs();
        productAttrValueService.saveProductAttrValue(spuId,baseAttrs);

        //5.保存spu的积分信息  shop-sms->sms_spu_bounds
        Bounds bounds = vo.getBounds();
        SpuBoundTo spuBoundTo = new SpuBoundTo();
        BeanUtils.copyProperties(bounds,spuBoundTo);
        spuBoundTo.setSpuId(spuId);
        //TODO 远程调用coupon模块分布式事务处理
        try {
            R r = couponFeignService.saveSpuBounds(spuBoundTo);
        } catch (Exception e) {
            log.error("SpuInfoServiceImpl:saveSpuInfo调用远程couponFeignService.saveSpuBounds(spuBoundTo)失败,原因{}",e.getMessage());
        }

        //6.保存当前spu对应的sku信息
        List<Skus> skus = vo.getSkus();
        //6.1）sku的基本信息  pms_sku_info
        //6.2）保存sku的图片信息  pms_sku_images
        //6.3）sku销售属性信息 pms_sku_sale_attr_value
        //6.4）sku的满减优惠信息  shop-sms->sms_sku_full_reduction\sms_sku_ladder\sms_member_price
        skuInfoService.saveSkuInfo(spuInfoEntity,skus);
    }

    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        QueryWrapper<SpuInfoEntity> wrapper = new QueryWrapper<>();
        //如果分类Id存在
        String catelogId = (String) params.get("catelogId");
        if(!StringUtils.isEmpty(catelogId) && !"0".equals(catelogId)){
            wrapper.eq("catalog_id",catelogId);
        }


        //如果品牌Id存在
        String brandId = (String) params.get("brandId");
        if(!StringUtils.isEmpty(brandId) && !"0".equals(brandId)){
            wrapper.eq("brand_id",brandId);
        }

        //状态
        String status = (String) params.get("status");
        if(!StringUtils.isEmpty(status)){
            wrapper.eq("publish_status",status);
        }

        //检索条件
        String key = (String) params.get("key");
        if(!StringUtils.isEmpty(params.get("key"))){
            wrapper.and(w->{
                w.eq("id",key).or().like("spu_name",key);
            });
        }

        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),wrapper
        );

        return new PageUtils(page);
    }


    /**
     * 商品上架
     * @param spuId
     */
    @Override
    public void spuUpById(Long spuId) {
        //1. 根据spuid查询对应下的所有sku
        QueryWrapper<SkuInfoEntity> wr = new QueryWrapper<>();
        wr.eq("spu_id",spuId);
        List<SkuInfoEntity> list = skuInfoService.list(wr);

        //2. 循环封装SkuEsModel
        //2.1 根据spuid查询SkuEsModel中有而sku中没有的字段
        SpuInfoEntity spuEntity = this.getById(spuId);
        if(spuEntity == null){
            log.error("SkuInfoServiceImpl:spuUpById 查询spu失败");
            return;
        }
        CategoryEntity categoryEntity = categoryService.getById(spuEntity.getCatalogId());
        BrandEntity brandEntity = brandService.getById(spuEntity.getBrandId());

        String categoryName = "";
        if(categoryEntity != null)  categoryName = categoryEntity.getName();
        String brandName = "";
        String brandLog = "";
        if(brandEntity != null){
            brandName = brandEntity.getName();
            brandLog = brandEntity.getLogo();
        }

        // 发送远程调用查询每个sku是否有库存，建议只发送一次远程调用
        List<Long> skuIds = list.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());
        Map<Long, Boolean> skuHasStockMap = null;
        try {
            //远程调用有失败的风险所以要在try里面
            R r = wareFeignService.hasStock(skuIds);
            List<SkuHasStockTo> skuHasStockTos = JSON.parseObject(r.getData(), new TypeReference<List<SkuHasStockTo>>(){});
            skuHasStockMap = skuHasStockTos.stream().collect(Collectors.toMap(SkuHasStockTo::getSkuId, SkuHasStockTo::getHasStock));
        } catch (Exception e) {
            log.error("SkuInfoServiceImpl:spuUpById 调用ware服务异常{}",e.getMessage());
        }


        List<SkuEsModel.AttrEs> attrs = getAttrs(spuId);
        //装配skuEsModel
        String finalBrandName = brandName;
        String finalBrandLog = brandLog;
        String finalCategoryName = categoryName;
        Map<Long, Boolean> finalSkuHasStockMap = skuHasStockMap;
        List<SkuEsModel> collect = list.stream().map(item -> {
            SkuEsModel skuEsModel = new SkuEsModel();
            BeanUtils.copyProperties(item,skuEsModel);
            skuEsModel.setBrandName(finalBrandName);
            skuEsModel.setBrandImg(finalBrandLog);
            skuEsModel.setCatalogName(finalCategoryName);
            skuEsModel.setSkuPrice(item.getPrice());
            skuEsModel.setSkuImg(item.getSkuDefaultImg());
            skuEsModel.setHotScore(0L);

            skuEsModel.setAttrs(attrs);

            if(finalSkuHasStockMap != null) {
                skuEsModel.setHasStock(finalSkuHasStockMap.get(item.getSkuId()));
            }else{
                skuEsModel.setHasStock(false);
            }

            return skuEsModel;
        }).collect(Collectors.toList());
        log.info("collect的值是{}",collect);

        // 调用远程服务，将上架的商品保存到es中
        try {
            R r = thirdFeignService.productStatusUp(collect);
            if(r.getCode() == 0){
                //调用成功修改spu状态为上架
                baseMapper.updateSpuStatus(spuId, ProductConstant.SPuStatus.UP_SPU.getCode());
            }else{
                //调用失败
                // TODO 重复调用，接口幂等性，重试机制
            }
        } catch (Exception e) {
            log.error("SkuInfoServiceImpl:spuUpById 调用第三方服务的elastsearch服务异常{}",e.getMessage());
        }

    }

    /**
     * 根据spuid查询符合条件的attr
     * @param spuId
     * @return
     */
    public List<SkuEsModel.AttrEs> getAttrs(Long spuId){
        //1. 根据spuId在product_attr_value中查询出对应的attr的值和id
        List<ProductAttrValueEntity> attrList = productAttrValueService.baseAttrForSpu(spuId);
        List<Long> attrIds = attrList.stream().map(item -> item.getAttrId()).collect(Collectors.toList());

        QueryWrapper<AttrEntity> attrWr = new QueryWrapper<>();
        attrWr.eq("search_type",1);
        if(attrIds.size() > 0) attrWr.in("attr_id",attrIds);
        List<Long> attrIdList = attrService.list(attrWr).stream().map(item -> item.getAttrId()).collect(Collectors.toList());
        HashSet<Long> attrsSet = new HashSet<>(attrIdList);

        List<SkuEsModel.AttrEs> collect = attrList.stream()
                .filter(item -> attrsSet.contains(item.getAttrId()))
                .map(item -> {
                    SkuEsModel.AttrEs attrEs = new SkuEsModel.AttrEs();
                    attrEs.setAttrId(item.getAttrId());
                    attrEs.setAttrName(item.getAttrName());
                    attrEs.setAttrValue(item.getAttrValue());
                    return attrEs;
                }).collect(Collectors.toList());
        return collect;
    }

    /**
     * 根据传递过来的skuids获取对应的spu信息
     * @param skuIds
     * @return
     */
    @Override
    public Map<Long,SpuInfoVo> getSpuInfoBySkuIds(List<Long> skuIds) {
        List<SkuInfoEntity> skuInfoEntities = skuInfoService.listByIds(skuIds);
        return skuInfoEntities.stream().collect(Collectors.toMap(SkuInfoEntity::getSkuId, item -> {
            SpuInfoVo spuInfoVo = new SpuInfoVo();
            SpuInfoEntity entity = this.getById(item.getSpuId());
            BeanUtils.copyProperties(entity,spuInfoVo);
            BrandEntity brandEntity = brandService.getById(entity.getBrandId());
            if(brandEntity != null) spuInfoVo.setBrandName(brandEntity.getName());
            return spuInfoVo;
        }));
    }
}